package xin.marcher.module.quality.job;

import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import xin.marcher.module.common.core.PageResult;
import xin.marcher.module.common.enums.YesOrNoEnum;
import xin.marcher.module.common.exception.BaseBizException;
import xin.marcher.module.common.redis.RedisLock;
import xin.marcher.module.common.utils.DateFormatUtil;
import xin.marcher.module.quality.cor.impl.*;
import xin.marcher.module.quality.domain.dto.ItemQualityControlResultDTO;
import xin.marcher.module.quality.domain.entity.ItemQualityControlSurveyTaskDO;
import xin.marcher.module.quality.domain.entity.ItemQualityControlWhitelistDO;
import xin.marcher.module.quality.domain.request.SurveyTaskRequest;
import xin.marcher.module.quality.repository.ItemQualityControlRepository;
import xin.marcher.module.quality.repository.SurveyRepository;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import static xin.marcher.module.common.constants.quality.QualityRedisKeyConstant.RISK_DATA_LOCK;

/**
 *
 */
@Slf4j
@Component
public class QualitySchedule {

    @Autowired
    private ItemQualityControlRepository itemQualityControlRepository;

    @Autowired
    private RiskResultHandler riskResultHandler;

    @Autowired
    private RiskDataHandler riskDataHandler;

    @Autowired
    private SurveyPoolHandler surveyPoolHandler;

    @Autowired
    private SurveyTaskPoolHandler surveyTaskPoolHandler;

    @Autowired
    private QualityWhitelistHandler qualityWhitelistHandler;

    @Autowired
    private RedisLock redisLock;

    @Autowired
    private SurveyRepository surveyRepository;

    /**
     * 分布式锁失效时间
     */
    private final static Integer RISK_DATA_LOCK_INVALID_TIME = 10;

    /**
     * 定时数据集市中的风险商品数据，写入到风险商品列表
     */
    @XxlJob("pullRiskData")
    @Transactional(rollbackFor = Exception.class)
    public void pullRiskData() {
        try {
            if (!redisLock.lock(RISK_DATA_LOCK, RISK_DATA_LOCK_INVALID_TIME)) {
                return;
            }

            // 从数据集市提供的数据中拉取风险数据
            Map<String, ItemQualityControlResultDTO> riskDataMap = itemQualityControlRepository.queryRiskData();

            // 初始化处理链
            RiskHandlerChain riskFilterChain = RiskHandlerChain.obtainRiskHandlerChain(
                    riskResultHandler,
                    riskDataHandler,
                    surveyPoolHandler,
                    surveyTaskPoolHandler,
                    qualityWhitelistHandler);

            // 处理结果数据
            Map<String, ItemQualityControlResultDTO> resultMap = riskFilterChain.handle(riskDataMap);

            // 写入风险商品列表
            itemQualityControlRepository.insertRiskData(resultMap.values());
        } finally {
            redisLock.unlock(RISK_DATA_LOCK);
        }
    }

    /**
     * 扫描出超过期限，并且状态为生效状态的白名单记录，使它们失效
     */
    @XxlJob("invalidWhitelist")
    @Transactional(rollbackFor = Exception.class)
    public void invalidWhitelist() {
        // 超过期限的生效状态的白名单记录
        List<ItemQualityControlWhitelistDO> itemQualityControlWhitelistDOList = itemQualityControlRepository.queryWhitelist();
        // 设置为失效状态
        itemQualityControlRepository.invalidWhitelist(itemQualityControlWhitelistDOList);
    }

    @XxlJob("handleExceedDeadlineTask")
    public void handleExceedDeadlineTask() {
        // 1.从原始数据表中分页获取初始数据，按照日期，每天调度一次，每天获取前一天的数据
        SurveyTaskRequest request = new SurveyTaskRequest();
        Date deadLine = new Date();

        String dateStr = DateFormatUtil.format(deadLine);
        try {
            deadLine = DateFormatUtil.StringToDate(dateStr);
        } catch (Exception e) {
            log.error("日期格式转换错误！error:{}", e);
        }
        request.setDeadlineStatus(YesOrNoEnum.YES.getCode());
        request.setDeadline(deadLine);
        // 批量设置超时未上传资料的调查任务未调查不通过
        autoBatchUnpassSurveyTask(request);

    }

    @Transactional(rollbackFor = Exception.class)
    private void autoBatchUnpassSurveyTask(SurveyTaskRequest request) {
        PageResult<ItemQualityControlSurveyTaskDO> page = null;
        // 循环不断获取数据，对未上传资料数据进行处理
        // 由于数据量比较小，所以没有采取分布式锁获取数据的方式，在使用xxljob调度的时候，设置调度服务器为其中一台机器即可
        // 即使出现了重复的处理也问题不大，最终数据还是会设置成不通过状态
        while (true) {
            try {// 获取一批数据
                page = surveyRepository.scheduleSurveyTaskList(request);
                if (Objects.isNull(page) || CollectionUtils.isEmpty(page.getContent())) {
                    break;
                }
                // 直接设置这批数据状态不通过
                List<Long> list = page.getContent().stream().map(ItemQualityControlSurveyTaskDO::getId)
                        .collect(Collectors.toList());
                surveyRepository.batchUnpassSurveyTaskById(list);
            } catch (Exception e) {
                log.info("error:{}", e);
                throw new BaseBizException("批量处理逾期未上传资质材料数据失败");
            }
        }
    }

}
